package com.inspection.service.impl;

import com.google.common.collect.Lists;
import com.inspection.dao.SysDictDao;
import com.inspection.entity.InspectionRegulationDO;
import com.inspection.entity.SysDictDO;
import com.inspection.model.dto.SysDictDTO;
import com.inspection.model.dto.SysDictQueryDTO;
import com.inspection.model.vo.SysDictQueryVO;
import com.inspection.service.SysDictService;
import com.inspection.support.AssertUtils;
import com.inspection.support.ExcelUtils;
import com.inspection.support.PageHelper;
import com.inspection.support.model.BusinessBaseException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhaoqi
 * @since 2020-12-14
 */
@Service
public class SysDictServiceImpl implements SysDictService {

   static  List<Sort.Order> sortList = new ArrayList<>();

    static {
        sortList.add(new Sort.Order(Sort.Direction.ASC, "type"));
        sortList.add(new Sort.Order(Sort.Direction.ASC, "code"));
        sortList.add(new Sort.Order(Sort.Direction.ASC, "orderNum"));

    }



    @Autowired
    private SysDictDao sysDictDao;

    @PersistenceContext
    private EntityManager em;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveDict(SysDictDTO save) {

        AssertUtils.nonNull(save.getType(), "type不能为空！");
        AssertUtils.nonNull(save.getCode(), "code不能为空！");


        //同一个类型下 code不能重复
        SysDictDO dictQuery = new SysDictDO();
        dictQuery.setType(save.getType());
        dictQuery.setCode(save.getCode());
        Optional<SysDictDO> dictOp = sysDictDao.findOne(Example.of(dictQuery));
        if (dictOp.isPresent()) {
            throw new BusinessBaseException("已存在该类型下code相同的数据");
        }

        SysDictDO saveDO = new SysDictDO();
        BeanUtils.copyProperties(save, saveDO);
        saveDO.setIsDel(0);
        sysDictDao.save(saveDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDict(SysDictDTO update) {
        AssertUtils.nonNull(update.getId(), "字典id不能为空");
        Optional<SysDictDO> dictOp = sysDictDao.findById(update.getId());
        if (!dictOp.isPresent()) {
            throw new BusinessBaseException("字典不存在！");
        }


        SysDictDO dictUpdate = dictOp.get();
        //如果发生了type+code任何一个变化 都需要验证
        if (!Objects.equals(update.getType(), dictUpdate.getType()) || !Objects.equals(update.getCode(), dictUpdate.getCode())) {
            SysDictDO dictQuery = new SysDictDO();
            dictQuery.setType(update.getType());
            dictQuery.setCode(update.getCode());
            Optional<SysDictDO> existOp = sysDictDao.findOne(Example.of(dictQuery));
            if (existOp.isPresent()) {
                throw new BusinessBaseException("已存在该类型下code相同的数据");
            }
        }

        dictUpdate.setCode(update.getCode());
        dictUpdate.setType(update.getType());
        dictUpdate.setName(update.getName());
        dictUpdate.setValue(update.getValue());
        dictUpdate.setRemark(update.getRemark());
        sysDictDao.saveAndFlush(dictUpdate);
    }

    @Override
    public SysDictQueryVO queryDict(SysDictQueryDTO query) {

        List<SysDictDO> dicts = sysDictDao.findAll(buildSpecification(query), Sort.by(sortList));
        if (CollectionUtils.isEmpty(dicts)) {
            return SysDictQueryVO.builder().build();
        }
        Map<String, List<SysDictDO>> typeMap = dicts.stream().collect(Collectors.groupingBy(SysDictDO::getType));

        return SysDictQueryVO.builder().typeMap(typeMap).build();
    }

    @Override
    public Page<SysDictDO> pageDict(SysDictQueryDTO page) {


        PageHelper check = PageHelper.check(page.getPageNo(), page.getPageSize());
        Pageable pageable = PageRequest.of(check.getOffset(), check.getPageSize(), Sort.by(sortList));

        return sysDictDao.findAll(buildSpecification(page), pageable);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delDict(SysDictDTO del) {
        AssertUtils.nonNull(del.getId(), "字典id不能为空");
        Optional<SysDictDO> dictOp = sysDictDao.findById(del.getId());
        if (!dictOp.isPresent()) {
            throw new BusinessBaseException("字典不存在！");
        }
        sysDictDao.delete(dictOp.get());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelDict(SysDictDTO del) {
        AssertUtils.nonNull(del.getIdList(), "字典id不能为空");

        List<SysDictDO> dictDOS = sysDictDao.findAllById(del.getIdList());
        if (CollectionUtils.isEmpty(dictDOS)) {
            throw new BusinessBaseException("字典不存在！");
        }
        sysDictDao.deleteInBatch(dictDOS);

    }

    /**
     * 获取字段目录
     *
     * @param query
     * @return
     */
    @Override
    public List<SysDictDO> queryDictCatalogue(SysDictQueryDTO query) {

        SysDictDO dictQuery = new SysDictDO();
        dictQuery.setIsDel(0);
        List<SysDictDO> dicts = sysDictDao.findAll(Example.of(dictQuery));
        if(CollectionUtils.isEmpty(dicts)){
            return new ArrayList<>();
        }
        Map<String, SysDictDO> collect = dicts.stream().collect(Collectors.toMap(SysDictDO::getType, InspectionDepartmentDO -> InspectionDepartmentDO, (v1, v2) -> v1));

        return  new ArrayList<>(collect.values());

    }

    @Override
    public SysDictDO getDict(SysDictDTO get) {
        AssertUtils.nonNull(get.getId(), "字典id不能为空");
        Optional<SysDictDO> dictOp = sysDictDao.findById(get.getId());
        if (!dictOp.isPresent()) {
            throw new BusinessBaseException("字典不存在！");
        }
        return dictOp.get();
    }


    protected Specification<SysDictDO> buildSpecification(SysDictQueryDTO query){
        return (Specification<SysDictDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            if(!StringUtils.isEmpty(query.getType())){
                predicates.add(criteriaBuilder.equal(root.get("type"), query.getType()));
            }
            if(!StringUtils.isEmpty(query.getName())){
                predicates.add(criteriaBuilder.like(root.get("name"),"%"+ query.getName()+"%"));
            }
            if(!StringUtils.isEmpty(query.getValue())){
                predicates.add(criteriaBuilder.like(root.get("value"),"%"+ query.getValue()+"%"));
            }

            if (!CollectionUtils.isEmpty(query.getTypeList())) {
                CriteriaBuilder.In<Object> in = criteriaBuilder.in(root.get("type"));
                for (String typeItem : query.getTypeList()) {
                    in.value(typeItem);
                }
                predicates.add(in);
            }

            predicates.add(criteriaBuilder.equal(root.get("isDel"),0));
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    }
}
